package com.philip.journal.core.controller;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletResponse;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import net.sf.json.JSONSerializer;

import org.apache.log4j.Logger;

import com.philip.journal.common.StringUtils;
import com.philip.journal.home.service.util.BeanToMapConverter;

/** JSON specific response handler. */
public class JsonResponseHandler implements ResponseHandler {

    /** JSON attribute to identify if leaf or branch. */
    public static final String ISLEAF = "leaf";

    /** JSON attribute ID. */
    public static final String JSON_ID = "id";

    /** Sub class reusable logger instance. */
    private final Logger logger = Logger.getLogger(getClass()); // NOPMD by r39 on 3/30/11 11:47 AM

    /** Reference holder to conversion factory map. IOC configured. */
    private transient Map<String, BeanToMapConverter> convFactoryMap;

    /**
     * Sets response header.
     *
     * @param response standard servlet response instance.
     */
    @SuppressWarnings("unused")
    private void setHeader(final HttpServletResponse response) {
        response.setContentType("Cache-Control: no-cache, must-revalidate");
        response.setContentType("application/json");
    }

    @Override
    public final void respondSuccess(final HttpServletResponse response) throws IOException {
        final PrintWriter writer = response.getWriter();
        final JSONObject jsonObject = new JSONObject();
        jsonObject.element(SUCCESS, true);
        writer.print(jsonObject);
        writer.close();
    }

    @Override
    public final void respondSuccess(final HttpServletResponse response, final Map<String, Object> param)
            throws IOException {
        final PrintWriter writer = response.getWriter();
        final JSONObject jsonObject = new JSONObject();
        for (final String key : param.keySet()) {
            jsonObject.element(key, param.get(key));
        }
        jsonObject.element(SUCCESS, true);
        logger.debug(jsonObject);
        writer.print(jsonObject);
        writer.close();
    }

    @Override
    public final void respondSuccess(final HttpServletResponse response, final Map<String, Object> param,
            final String holder) throws IOException {
        final PrintWriter writer = response.getWriter();
        final JSONObject jsonObject = new JSONObject();

        final JSONObject holderJsonObject = new JSONObject();

        for (final String key : param.keySet()) {
            jsonObject.element(key, param.get(key));//Inefficient? How am I suppose to invoke element method then?
        }

        holderJsonObject.element(SUCCESS, true);
        holderJsonObject.element(holder, jsonObject);
        logger.debug(getStringUtils().removeHtmlTags(holderJsonObject.toString()));
        writer.print(holderJsonObject);
        writer.close();
    }

    @Override
    public final <T> void respondList(final HttpServletResponse response, final List<T> list,
            final BeanToMapConverter converter) throws IOException {
        final PrintWriter writer = response.getWriter();
        final JSONArray jsonArray = new JSONArray();
        for (final T next : list) {
            final JSONObject jsonObject = (JSONObject) JSONSerializer.toJSON(converter == null ? next : converter
                    .convert(next));
            jsonArray.element(jsonObject);
        }
        logger.debug(getStringUtils().removeHtmlTags(jsonArray.toString()));
        writer.print(jsonArray);
        writer.close();
    }

    @Override
    public final <T> void respondListHolder(final HttpServletResponse response, final List<T> list,
            final String placeHolder) throws IOException {
        final PrintWriter writer = response.getWriter();
        final JSONArray jsonArray = new JSONArray();
        for (final T next : list) {
            final JSONObject jsonObject = (JSONObject) JSONSerializer.toJSON(next);
            jsonArray.element(jsonObject);
        }

        final JSONObject jsonObjectOut = new JSONObject();
        jsonObjectOut.put(placeHolder, jsonArray);
        writer.print(jsonObjectOut);
        writer.close();
    }

    @Override
    public final void respondFail(final HttpServletResponse response, final String errorMessage) throws IOException {
        final PrintWriter writer = response.getWriter();
        final Map<String, Object> result = new HashMap<String, Object>();
        result.put(SUCCESS, false);
        result.put(ERRORMSG, errorMessage);
        writer.print(JSONSerializer.toJSON(result));
        writer.close();
    }

    @Override
    public final void respondFail(final HttpServletResponse response, final Map<String, String> errors)
            throws IOException {
        final PrintWriter writer = response.getWriter();
        final Map<String, Object> result = new HashMap<String, Object>();
        result.put(SUCCESS, false);
        result.put(ERRORS, errors);
        writer.print(JSONSerializer.toJSON(result));
        writer.close();
    }

    @Override
    public final void respondFail(final HttpServletResponse response, final Map<String, String> errors,
            final String errorMsg) throws IOException {
        final PrintWriter writer = response.getWriter();
        final Map<String, Object> result = new HashMap<String, Object>();
        result.put(SUCCESS, false);
        result.put(ERRORS, errors);
        result.put(ERRORMSG, errorMsg);
        writer.print(JSONSerializer.toJSON(result));
        writer.close();
    }

    @Override
    public final void respondFail(final HttpServletResponse response, final String errorShort, final String errorLong)
            throws IOException {
        final PrintWriter writer = response.getWriter();
        final Map<String, Object> result = new HashMap<String, Object>();
        result.put(SUCCESS, false);
        result.put(DESC_SHORT, errorShort);
        result.put(DESC_LONG, errorLong);
        writer.print(JSONSerializer.toJSON(result));
        writer.close();
    }

    /**
     * @param pConvFactoryMap new conversion factory map provided by IOC container.
     */
    public final void setConverterFactoryMap(final Map<String, BeanToMapConverter> pConvFactoryMap) {
        this.convFactoryMap = pConvFactoryMap;
    }

    @Override
    public final Map<String, BeanToMapConverter> getConverterFactoryMap() {
        return convFactoryMap;
    }

    @Override
    public final void respondCustom(final HttpServletResponse response, final Map<String, Object> respObj)
            throws IOException {
        final PrintWriter writer = response.getWriter();
        writer.print(JSONSerializer.toJSON(respObj));
        writer.close();
    }

    StringUtils getStringUtils() {
        return StringUtils.getInstance();
    }
}
